#include "glib.h"
#include "carray.h"

int g_file_test(const char* path, int t)
{
    return !access(path, t);
}

char* g_strdup_vprintf(const char* fmt, va_list args)
{
    char* ret = NULL;
    vasprintf(&ret, fmt, args);
    return ret;
}

/**
 * g_error_new_valist:
 * @domain: error domain
 * @code: error code
 * @format: printf()-style format for error message
 * @args: #va_list of parameters for the message format
 *
 * Creates a new #GError with the given @domain and @code,
 * and a message formatted with @format.
 *
 * Returns: a new #GError
 *
 * Since: 2.22
 */
GError*
g_error_new_valist(GQuark domain,
    gint code,
    const gchar* format,
    va_list args)
{
    GError* error;

    /* Historically, GError allowed this (although it was never meant to work),
   * and it has significant use in the wild, which g_return_val_if_fail
   * would break. It should maybe g_return_val_if_fail in GLib 4.
   * (GNOME#660371, GNOME#560482)
   */
    g_warn_if_fail(domain != 0);
    g_warn_if_fail(format != NULL);

    error = g_slice_new(GError);

    error->domain = domain;
    error->code = code;
    error->message = g_strdup_vprintf(format, args);

    return error;
}

gboolean g_error_matches(const GError* error, GQuark domain, gint code)
{
    return error && error->domain == domain && error->code == code;
}

/**
 * g_set_error:
 * @err: (out callee-allocates) (optional): a return location for a #GError
 * @domain: error domain
 * @code: error code
 * @format: printf()-style format
 * @...: args for @format
 *
 * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err
 * must be %NULL. A new #GError is created and assigned to *@err.
 */
void g_set_error(GError** err, GQuark domain, gint code, const gchar* format, ...)
{
    GError* new;

    va_list args;

    if (err == NULL)
        return;

    va_start(args, format);
    new = g_error_new_valist(domain, code, format, args);
    va_end(args);

    if (*err == NULL)
        *err = new;
    else {
        printf("ERROR_OVERWRITTEN_WARNING:%s\n", new->message);
        g_error_free(new);
    }
}

int g_io_error_from_errno(gint err_no)
{
    return err_no;
}

void g_strfreev(gchar** str_array)
{
    if (str_array) {
        gsize i;

        for (i = 0; str_array[i] != NULL; i++)
            g_free(str_array[i]);

        g_free(str_array);
    }
}

GQuark g_quark_from_static_string(const gchar* string)
{
    return (GQuark)string;
}

/**
 * g_strsplit:
 * @string: a string to split
 * @delimiter: a string which specifies the places at which to split
 *     the string. The delimiter is not included in any of the resulting
 *     strings, unless @max_tokens is reached.
 * @max_tokens: the maximum number of pieces to split @string into.
 *     If this is less than 1, the string is split completely.
 *
 * Splits a string into a maximum of @max_tokens pieces, using the given
 * @delimiter. If @max_tokens is reached, the remainder of @string is
 * appended to the last token.
 *
 * As an example, the result of g_strsplit (":a:bc::d:", ":", -1) is a
 * %NULL-terminated vector containing the six strings "", "a", "bc", "", "d"
 * and "".
 *
 * As a special case, the result of splitting the empty string "" is an empty
 * vector, not a vector containing a single string. The reason for this
 * special case is that being able to represent an empty vector is typically
 * more useful than consistent handling of empty elements. If you do need
 * to represent empty elements, you'll need to check for the empty string
 * before calling g_strsplit().
 *
 * Returns: a newly-allocated %NULL-terminated array of strings. Use
 *    g_strfreev() to free it.
 */
gchar** g_strsplit(const gchar* string, const gchar* delimiter, gint max_tokens)
{
    char* s;
    const gchar* remainder;
    g_return_val_if_fail(string != NULL, NULL);
    g_return_val_if_fail(delimiter != NULL, NULL);
    g_return_val_if_fail(delimiter[0] != '\0', NULL);

    if (max_tokens < 1)
        max_tokens = INT32_MAX;

    Arr *string_list = ArrNew();
    remainder = string;
    s = strstr(remainder, delimiter);
    if (s) {

        gsize delimiter_len = strlen(delimiter);

        while (--max_tokens && s) {
            gsize len;

            len = s - remainder;

            ArrAdd(string_list, strndup(remainder, len));
            remainder = s + delimiter_len;
            s = strstr(remainder, delimiter);
        }
    }
    ArrAdd(string_list, NULL);

    return (gchar **)ArrCPtr(string_list);
}

/**
 * g_propagate_error:
 * @dest: (out callee-allocates) (optional) (nullable): error return location
 * @src: (transfer full): error to move into the return location
 *
 * If @dest is %NULL, free @src; otherwise, moves @src into *@dest.
 * The error variable @dest points to must be %NULL.
 *
 * @src must be non-%NULL.
 *
 * Note that @src is no longer valid after this call. If you want
 * to keep using the same GError*, you need to set it to %NULL
 * after calling this function on it.
 */
void g_propagate_error(GError** dest, GError* src)
{
    g_return_if_fail(src != NULL);

    if (dest == NULL) {
        if (src)
            g_error_free(src);
        return;
    } else {
        if (*dest != NULL) {
            printf("ERROR_OVERWRITTEN_WARNING:%s\n", src->message);
            g_error_free(src);
        } else
            *dest = src;
    }
}

gboolean g_file_get_contents(const gchar* filename, gchar** contents, gsize* length, GError** error)
{
    gboolean ret = false;
    FILE* fp = fopen(filename, "rb");
    if (fp) {
        fseek(fp, 0, SEEK_END);
        *length = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        *contents = (gchar*)malloc(*length);
        size_t readlen = 0;
        while ((readlen = fread(*contents, 1, *length, fp)) > 0)
            ;
        fclose(fp);
        ret = true;
    }
    return ret;
}
